package com.chatplus.application.service.auth.authentication.impl;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.chatplus.application.common.exception.ServiceException;
import com.chatplus.application.common.logging.SouthernQuietLogger;
import com.chatplus.application.common.logging.SouthernQuietLoggerFactory;
import com.chatplus.application.common.util.AddressUtils;
import com.chatplus.application.domain.entity.account.UserEntity;
import com.chatplus.application.domain.entity.account.UserLoginLogEntity;
import com.chatplus.application.domain.response.AccountLoginResponse;
import com.chatplus.application.service.account.UserLoginLogService;
import com.chatplus.application.service.account.UserService;
import com.chatplus.application.service.auth.authentication.AuthenticationProvider;
import com.chatplus.application.service.auth.authentication.AuthenticationToken;
import com.chatplus.application.service.auth.authentication.UserAuthenticationService;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.util.Collection;

@Component
public class LoginFormUserAuthenticationServiceImpl implements UserAuthenticationService {
    private static final SouthernQuietLogger LOGGER = SouthernQuietLoggerFactory.getLogger(LoginFormUserAuthenticationServiceImpl.class);
    private final Collection<AuthenticationProvider> authenticationProviders;
    private final UserService userService;
    private final UserLoginLogService userLoginLogService;

    public LoginFormUserAuthenticationServiceImpl(Collection<AuthenticationProvider> authenticationProviders
            , UserService userService
            , UserLoginLogService userLoginLogService) {
        this.authenticationProviders = authenticationProviders;
        this.userService = userService;
        this.userLoginLogService = userLoginLogService;
    }


    @Override
    @Transactional
    public AccountLoginResponse authenticate(AuthenticationToken authenticationToken) {

        for (AuthenticationProvider authenticationProvider : authenticationProviders) {
            if (authenticationProvider.supports(authenticationToken)) {
                LOGGER.message("使用" + authenticationProvider.getName() + "进行登录")
                        .context("authenticationToken", authenticationToken)
                        .debug();
                AccountLoginResponse authentication;
                authentication = authenticationProvider.authenticate(authenticationToken);
                // 设置token
                authenticationProvider.onAuthenticationSuccess(authentication);
                // 设置
                userService.update(new LambdaUpdateWrapper<UserEntity>()
                        .set(UserEntity::getLastLoginAt, Instant.now())
                        .set(UserEntity::getLastLoginIp, authenticationToken.getRemoteIp())
                        .eq(UserEntity::getId, authentication.getId()));
                UserLoginLogEntity userLoginLogEntity = new UserLoginLogEntity();
                userLoginLogEntity.setUserId(authentication.getId());
                userLoginLogEntity.setLoginIp(authenticationToken.getRemoteIp());
                userLoginLogEntity.setUsername((String) authenticationToken.getUserPrincipal());
                userLoginLogEntity.setLoginAddress(AddressUtils.getRealAddressByIP(authenticationToken.getRemoteIp()));
                userLoginLogService.save(userLoginLogEntity);
                // 登录日志
                return authentication;
            }
        }
        //没有合适的认证处理器，直接返回未认证
        throw new ServiceException("登录失败", 401);
    }

    public LoginFormUserAuthenticationServiceImpl addAuthenticationProvider(AuthenticationProvider authenticationProvider) {
        authenticationProviders.add(authenticationProvider);
        return this;
    }
}
